// 引入第三方包
const Koa = require('koa')
const koaBody = require('koa-body')
const koaStatic = require('koa-static')
// 导入 CORS 中间件
const koaCors = require('@koa/cors')
// 导入错误处理中间件
const koaError = require('koa-json-error')
// 导入校验参数中间件
const koaParameter = require('koa-parameter')
// 导入jwt鉴权中间件
const koaJwt = require('koa-jwt')
const config = require('./config/config.default')


// 导入路由器实例
const router = require('./router')

// 导入数据库中间件
const mongoMiddleware = require('./middleware/mongodb')

// 创建koa实例
const app = new Koa()

// 注意第三方中间件顺序
// 1.根据依赖关系决定顺序,比如后面的报错都依赖于 koa-error 来处理错误信息,所以 koa-error 放在前面合适
// 2.根据流程决定顺序,比如 上传图片的流程: jwt鉴权 -> 获取body参数 -> 静态文件管理,中间件也要按这个顺序执行
// 3.解决跨域的中间件最好放最前面

// 第三方中间件
// 中间件：CORS 跨域
app.use(koaCors())
// 中间件：统一错误处理和错误信息输出
app.use(koaError({
    // 自定义出错时，接口返回数据的格式
    format: (err, obj) => {
        if (obj.code === 'INVALID_PARAM') {
            // 企业开发中基于安全考虑，对于参数校验错误，后端无需告知前端更多错误细节
            // （即只需告诉前端参数不合法即可）
            return {
                code: 40022,
                message: '存在不合法参数!'
            }
        } else if(obj.message === 'Authentication Error') {
            return {
                code: 40011,
                message: '鉴权失败!'
            }
        }
        return {
            code: obj.code || 50000,
            message: obj.message || err.message
        }
    }
}))
// 中间件：请求参数校验
// 使用 app.use 则会添加 koa-parameter 自己的错误处理中间件,就不会走我们的 koa-error 了,所以这里不需要app.use
// app.use(koaParameter(app))
koaParameter(app)
// 中间件：接口鉴权
app.use(koaJwt({
    secret: config.jwt.secret   // JWT 密钥
}).unless({
    // path: [/^\/api\/(?!user)/]  // 约定只对起始路径为 /api/user 的 API 接口进行鉴权
    path: [/^(?!\/api\/user)/]  // 约定只对起始路径为 /api/user 的 API 接口进行鉴权
}))
// 中间件: body参数辅助
app.use(koaBody({
    // 支持form-data格式参数
    multipart: true,
    // 文件上传配置
    formidable: {
        // 上传文件保存目录
        uploadDir: __dirname + '/static/uploads',
        // 保留上传文件后缀名
        keepExtensions: true
    }
}))
// 中间件：静态资源服务
app.use(koaStatic(__dirname + '/static'))
// 中间件：MongoDB 数据库操作辅助
app.use(mongoMiddleware())
// 中间件：路由相关
app.use(router.routes())
app.use(router.allowedMethods())

// 启动服务
app.listen(8000, () => {
    console.log(
        // ",--.   ,--.                           ,-------.,--.                     \n" +
        // "|  |   |  | ,--,--.,--,--,  ,---.     `--.   / |  ,---.  ,--,--. ,---.  \n" +
        // "|  |.'.|  |' ,-.  ||      \| .-. |      /   /  |  .-.  |' ,-.  || .-. | \n" +
        // "|   ,'.   |\ '-'  ||  ||  |' '-' '     /   `--.|  | |  |\ '-'  |' '-' ' \n" +
        // "'--'   '--' `--`--'`--''--'.`-  /     `-------'`--' `--' `--`--' `---'  \n" +
        // "                           `---'                                        \n" +
        "启动成功,端口号8000");
})